// v2.1.0 重点：
// - 新增ICS预览界面：支持课程预览、编辑、删除功能
// - 新增设置页面：用户友好的配置界面和首次使用引导
// - 新增自定义起始日期：用户可以设置学期起始日期
// - 优化数据传递：改进课程数据在页面间的传递机制
// - 解决"误报未生成任何课程"的弹窗：跨 iframe 选取"主 frame"后**仅该 frame**负责提示；其它 frame 静默退出。
// - 防重复下载：全局(顶层 window)加互斥标记，避免多 frame 同时触发下载。
// - 仅当确定 0 事件且全站没有其它 frame 生成过，才由"主 frame"弹一次提示。
// - 仍保留 v2.0 的：地点按周分配、lay-tips 强韧解析、样式位移→星期、明确时间段才生成等。

(function(){
  if (typeof window.__ics_mini__ !== "function") {
    window.__ics_mini__ = function() {
      const lines = ["BEGIN:VCALENDAR","VERSION:2.0","PRODID:-//SMU Timetable Export//CN","CALSCALE:GREGORIAN"];
      function pad(n){ return (n<10?'0':'')+n; }
      function toICSDate(d){
        const y=d.getFullYear(), m=pad(d.getMonth()+1), day=pad(d.getDate());
        const hh=pad(d.getHours()), mm=pad(d.getMinutes()), ss=pad(d.getSeconds());
        return `${y}${m}${day}T${hh}${mm}${ss}`;
      }
      function esc(s){ return String(s||'').replace(/([,;])/g,'\\$1').replace(/\n/g,'\\n'); }
      return {
        addEvent(title, desc, loc, start, end) {
          lines.push("BEGIN:VEVENT");
          lines.push("SUMMARY:"+esc(title || "课程"));
          if (desc) lines.push("DESCRIPTION:"+esc(desc));
          if (loc) lines.push("LOCATION:"+esc(loc));
          lines.push("DTSTART:"+toICSDate(start));
          lines.push("DTEND:"+toICSDate(end));
          lines.push("UID:" + (Date.now()+'-'+Math.random()).replace(/\D/g,''));
          lines.push("END:VEVENT");
        },
        download(filename){
          if (lines[lines.length-1] !== "END:VCALENDAR") lines.push("END:VCALENDAR");
          const blob = new Blob([lines.join("\r\n")], {type:"text/calendar"});
          const url = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href = url; a.download = filename || "timetable.ics";
          document.documentElement.appendChild(a); a.click();
          setTimeout(()=>{ URL.revokeObjectURL(url); a.remove(); }, 800);
          return blob;
        }
      };
    };
  }
})();

(function () {
  // 默认起始日期
  const DEFAULT_FIRST_MONDAY = new Date("2025-09-01");

  // —— 顶层互斥/通信 ——
  function getTop(){
    try { return window.top || window; } catch(e){ return window; }
  }
  const TOP = getTop();
  // 记录一次点击的“会话”时间戳，用于跨 frame 去重
  const SESSION = Date.now();
  if (!TOP.__SMU_ICS_SESS__ || (SESSION - (TOP.__SMU_ICS_SESS__||0) > 5000)) {
    TOP.__SMU_ICS_SESS__ = SESSION;
    TOP.__SMU_ICS_ANY_EVENTS__ = false;
    TOP.__SMU_ICS_MAIN_SCORE__ = -1;
  }

  // 判定本 frame 是否是“主 frame”（分数=含有明确时间段的 .fc-time 个数）
  function scoreThisFrame(){
    const times = Array.from(document.querySelectorAll('.fc-time'))
      .map(el => (el.getAttribute('data-full') || el.textContent || '').trim())
      .filter(t => /(\d{1,2}:\d{2})\s*-\s*(\d{1,2}:\d{2})/.test(t));
    return times.length;
  }
  const myScore = scoreThisFrame();
  try {
    if (myScore > (TOP.__SMU_ICS_MAIN_SCORE__||-1)) TOP.__SMU_ICS_MAIN_SCORE__ = myScore;
  } catch(e) {}

  // 非课表 frame 直接静默退出
  if (myScore === 0 && !document.querySelector('.fc-time-grid-event, .fc-event')) return;

  // —— 工具 ——
  const toMinutes = (t) => {
    const m = String(t||"").trim().match(/^(\d{1,2}):(\d{2})$/);
    if (!m) return null;
    const h = parseInt(m[1],10), mm = parseInt(m[2],10);
    return h*60 + mm;
  };
  const addMinutes = (date, minutes) => new Date(date.getTime() + minutes*60000);
  const startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
  const decodeEntities = (s) => { const t = document.createElement('textarea'); t.innerHTML = s || ''; return t.value || ''; };
  const stripCode = (name) => (name || '').replace(/^\[[^\]]+\]/,'').trim();
  const normKey = (s) => String(s||'').replace(/[：:\s\r\n\t\xa0]/g,'').trim();

  function parseWeeks(s){
    if (!s) return [];
    const list = String(s).replace(/第|周/g,'').trim();
    const set = new Set();
    list.split(/[、,，;；]\s*/).forEach(part=>{
      const m = part.match(/^\s*(\d+)\s*[-~到至]\s*(\d+)\s*$/);
      if (m){
        let a = parseInt(m[1],10), b = parseInt(m[2],10);
        if (!isNaN(a)&&!isNaN(b)){
          if (a>b) [a,b]=[b,a];
          for (let w=a; w<=b; w++) set.add(w);
        }
      } else {
        const n = parseInt(part,10);
        if (!isNaN(n)) set.add(n);
      }
    });
    return Array.from(set).sort((a,b)=>a-b);
  }

  function parseRoomMapping(roomText){
    if (!roomText) return [];
    let txt = roomText.replace(/\s+/g,' ').trim();
    if (/(不用场地|无|线上|暂无)/.test(txt)) return [];
    const re = /\[([^\]]+?)\]/g;
    let lastIndex = 0;
    let currRoom = null;
    const mappings = [];
    let m;
    while ((m = re.exec(txt))){
      const before = txt.slice(lastIndex, m.index).trim().replace(/[，,;；]+$/,'').trim();
      if (before) currRoom = before;
      const weeks = parseWeeks(m[1]);
      if (currRoom && weeks.length){
        mappings.push({ room: currRoom, weeks });
      }
      lastIndex = re.lastIndex;
    }
    if (!mappings.length && txt) return [{ room: txt, weeks: [] }];
    return mappings;
  }
  function roomForWeek(mappings, w){
    if (!mappings || !mappings.length) return '';
    const exact = mappings.find(x => x.weeks && x.weeks.includes(w));
    if (exact) return exact.room;
    const wildcard = mappings.find(x => !x.weeks || x.weeks.length===0);
    return wildcard ? wildcard.room : '';
  }

  function extractFromLayTips(el){
    const raw = el.getAttribute('lay-tips');
    if (!raw) return null;
    const decoded = decodeEntities(raw);
    const doc = new DOMParser().parseFromString(decoded, 'text/html');
    const kv = {};
    doc.querySelectorAll('tr').forEach(tr=>{
      const cells = Array.from(tr.children);
      for (let i=0;i<cells.length;i++){
        const c = cells[i];
        if (c.tagName?.toLowerCase()==='th'){
          const key = normKey(c.textContent);
          let val = '';
          for (let j=i+1;j<cells.length;j++){
            const nj = cells[j];
            if (nj.tagName?.toLowerCase()==='td'){ val = (nj.textContent||'').trim(); break; }
            if (nj.tagName?.toLowerCase()==='th'){ break; }
          }
          if (key) kv[key] = val;
        }
      }
    });
    function pick(...kws){
      for (const [k,v] of Object.entries(kv)){
        if (kws.some(w=>k.includes(normKey(w)))) return v;
      }
      return '';
    }
    function rx(label){
      const re = new RegExp(label+'\\s*</th>\\s*<td[^>]*>(.*?)</td>','i');
      const m = decoded.match(re);
      return m ? m[1].trim() : '';
    }
    const data = {
      course: pick('课程') || rx('课程'),
      type: pick('类型') || rx('类型'),
      teacher: pick('授课教师','教师') || rx('授课教师'),
      clazz: pick('上课班级','班级') || rx('上课班级'),
      hours: pick('学时') || rx('学时'),
      periods: pick('节次') || rx('节次'),
      weekday: pick('星期') || rx('星期'),
      weeksText: pick('上课周次','周次') || rx('上课周次'),
      room: pick('教学场地','教室','地点') || rx('教学场地'),
      seq: pick('课序号','序号') || rx('课序号')
    };
    data.roomMappings = parseRoomMapping(data.room);
    return data;
  }

  function deriveWeekdayFromStyle(el){
    const cs = getComputedStyle(el);
    let left = cs.left;
    if ((!left || left==='auto') && cs.inset){
      const parts = cs.inset.split(/\s+/);
      if (parts.length===4) left = parts[3];
    }
    if (left && left.endsWith('%')){
      const pct = parseFloat(left);
      const colWidth = 100/7;
      let idx = Math.round(pct/colWidth);
      idx = Math.max(0, Math.min(6, idx));
      return idx+1;
    }
    return null;
  }

  function* iterBlocks(){
    const blocks = document.querySelectorAll('.fc-time-grid-event, .fc-event');
    for (const el of blocks){
      const timeEl = el.querySelector('.fc-time');
      const timeText = (timeEl && (timeEl.getAttribute('data-full') || timeEl.textContent)) || '';
      const tm = String(timeText).trim().replace(/\s+/g,' ').match(/(\d{1,2}:\d{2})\s*-\s*(\d{1,2}:\d{2})/);
      if (!tm) continue;
      const startStr = tm[1], endStr = tm[2];

      const titleEl = el.querySelector('.fc-title');
      const fallbackTitle = titleEl ? (titleEl.innerText||'').split(/\n/).map(s=>s.trim()).filter(Boolean)[0] : '课程';

      const tips = extractFromLayTips(el) || {};
      const summary = stripCode(tips.course || fallbackTitle);

      let weekday = parseInt(String(tips.weekday).match(/\d+/)?.[0] || '', 10);
      if (!(weekday>=1 && weekday<=7)){
        const w2 = deriveWeekdayFromStyle(el);
        if (w2!=null) weekday = w2;
      }
      if (!(weekday>=1 && weekday<=7)) continue;

      let weeks = parseWeeks(tips.weeksText);
      if (!weeks.length){
        const txt = titleEl ? titleEl.innerText : '';
        const m2 = String(txt).match(/第?\s*(\d+(?:[-~到至]\d+)?(?:[、,，]\d+(?:[-~到至]\d+)?)*)\s*周/);
        if (m2) weeks = parseWeeks(m2[1]);
        if (!weeks.length){
          const m3 = String(txt).match(/\[(\d+(?:[-~到至]\d+)?)周\]/);
          if (m3) weeks = parseWeeks(m3[1]);
        }
      }
      if (!weeks.length) continue;

      const descParts = [];
      if (tips.type) descParts.push(`类型：${tips.type}`);
      if (tips.course) descParts.push(`课程：${tips.course}`);
      if (tips.teacher) descParts.push(`教师：${tips.teacher}`);
      if (tips.clazz) descParts.push(`班级：${tips.clazz}`);
      if (tips.hours) descParts.push(`学时：${tips.hours}`);
      if (tips.periods) descParts.push(`节次：${tips.periods}`);
      if (tips.weeksText) descParts.push(`上课周次：${tips.weeksText}`);
      if (tips.seq) descParts.push(`课序号：${tips.seq}`);
      if (tips.roomMappings && tips.roomMappings.length>1){
        const mapStr = tips.roomMappings.map(x => `${x.room} [${x.weeks && x.weeks.length ? x.weeks.join(',')+'周' : '全周'}]`).join('；');
        descParts.push(`地点映射：${mapStr}`);
      }
      const descBase = descParts.join('\n');

      yield { summary, startStr, endStr, weekday, weeks, roomMappings: tips.roomMappings, roomRaw: tips.room, descBase };
    }
  }

  function guessSemesterText(){
    const opt = document.querySelector('select[name="xnxqdm"] > option:checked');
    return opt ? opt.textContent.trim() : 'timetable';
  }

  async function main(){
    await new Promise(r=>setTimeout(r, 200));

    // 若已有其它 frame 在下载，直接退出
    if (TOP.__SMU_ICS_DOWNLOADING__) return;

    // 读取用户设置的起始日期
    let FIRST_MONDAY = DEFAULT_FIRST_MONDAY;
    
    try {
      const result = await chrome.storage.sync.get(['semesterStartDate']);
      
      if (result.semesterStartDate) {
        FIRST_MONDAY = new Date(result.semesterStartDate);
        // 验证日期是否有效
        if (isNaN(FIRST_MONDAY.getTime())) {
          FIRST_MONDAY = DEFAULT_FIRST_MONDAY;
        }
      }
    } catch (error) {
      console.warn('[SMU→ICS] 读取设置失败，使用默认日期:', error);
    }

    const cal = window.__ics_mini__();
    const xnText = guessSemesterText();
    let made = 0;

    for (const ev of iterBlocks()){
      const sM = toMinutes(ev.startStr);
      const eM = toMinutes(ev.endStr);
      if (sM==null || eM==null) continue;

      for (const w of ev.weeks){
        const base = new Date(FIRST_MONDAY);
        base.setDate(FIRST_MONDAY.getDate() + (w-1)*7 + (ev.weekday-1));
        const sod = startOfDay(base);
        const startDate = addMinutes(new Date(sod), sM);
        const endDate = addMinutes(new Date(sod), eM);
        const loc = (ev.roomMappings && ev.roomMappings.length) ?
          (function(){ const r = ev.roomMappings.find(x=>x.weeks?.includes(w)) || ev.roomMappings.find(x=>!x.weeks?.length); return r ? r.room : ''; })() :
          (ev.roomRaw || '');
        const desc = (ev.descBase ? ev.descBase + '\n' : '') + `展开周：第${w}周，星期${ev.weekday}`;

        cal.addEvent(ev.summary, desc, loc, startDate, endDate);
        made++;
      }
    }

    if (made>0){
      TOP.__SMU_ICS_ANY_EVENTS__ = true;
      if (!TOP.__SMU_ICS_DOWNLOADING__) {
        TOP.__SMU_ICS_DOWNLOADING__ = true;
        
        // 收集预览数据
        const previewEvents = [];
        for (const ev of iterBlocks()){
          const sM = toMinutes(ev.startStr);
          const eM = toMinutes(ev.endStr);
          if (sM==null || eM==null) continue;
          
          for (const w of ev.weeks){
            const base = new Date(FIRST_MONDAY);
            base.setDate(FIRST_MONDAY.getDate() + (w-1)*7 + (ev.weekday-1));
            const sod = startOfDay(base);
            const startDate = addMinutes(new Date(sod), sM);
            const endDate = addMinutes(new Date(sod), eM);
            const loc = (ev.roomMappings && ev.roomMappings.length) ?
              (function(){ const r = ev.roomMappings.find(x=>x.weeks?.includes(w)) || ev.roomMappings.find(x=>!x.weeks?.length); return r ? r.room : ''; })() :
              (ev.roomRaw || '');
            const desc = (ev.descBase ? ev.descBase + '\n' : '') + `展开周：第${w}周，星期${ev.weekday}`;
            
            previewEvents.push({
              title: ev.summary,
              start: startDate.toISOString(), // 转换为ISO字符串
              end: endDate.toISOString(),     // 转换为ISO字符串
              location: loc,
              description: desc,
              week: w,
              weekday: ev.weekday
            });
          }
        }
        
        // 打开预览页面而不是直接下载
        console.log('[SMU→ICS] 发送预览数据:', {
          eventsCount: previewEvents.length,
          filename: (xnText || 'timetable'),
          startDate: FIRST_MONDAY.toISOString().split('T')[0]
        });
        
        chrome.runtime.sendMessage({
          action: 'openPreview',
          data: {
            events: previewEvents,
            filename: (xnText || 'timetable'),
            startDate: FIRST_MONDAY.toISOString().split('T')[0]
          }
        });
        setTimeout(()=>{ TOP.__SMU_ICS_DOWNLOADING__ = false; }, 1500);
      }
      return; // 有结果就不弹窗
    }

    // 没生成事件：只有“主 frame”且全站都没生成过时，才提示一次
    setTimeout(()=>{
      const amIMain = (myScore === (TOP.__SMU_ICS_MAIN_SCORE__||-1));
      if (amIMain && !TOP.__SMU_ICS_ANY_EVENTS__) {
        alert('未成功生成任何课程。请确认：当前为整学期周视图、卡片上有时间段、弹窗含“上课周次/星期”。');
      }
    }, 500);
  }

  main().catch(e=>{
    console.error('[SMU→ICS] 运行错误：', e);
    alert('导出失败：' + e.message);
  });
})();